home *** CD-ROM | disk | FTP | other *** search
- dCRUNCH for Program Speed
- (PC Magazine Vol 5 No 13 Power User)
-
- In both "Pseudo Compiler for dBASE II" (PC Mag Vol 5 No 5 Power
- User) and "dBASE Speed Tips" (PC Mag Vol 5 No 1 Power User), the point
- is made that dBASE programs will execute faster if leading and trailing
- spaces, blank lines, and "*" lines are stripped out and if everything
- (except quoted text) is capitalized. (See the file DB3MISC.TXT for
- the articles cited here.)
- To facilitate the necessary file preparation, dCRUNCH.BAT and
- dSTRIP.COM will convert a 64K command file in under 6 seconds. Before
- running programs through the DOS filter, edit out any single apostrophes
- inside NOTE or TEXT/ENDTEXT statements, since capitalization is based
- on pairs of apostrophes, double quote, or brackets. Note also that
- everything inside a TEXT/ENDTEXT statement will be capitalized and
- left-justified unless you first enclose it in quotes, then edit out
- the quotes later.
- The syntax for the command is:
-
- DCRUNCH [d:][path][filename]
-
- and you should omit the .PRG filename extension.
- dBASE's interpreter is its weakest (slowest) link. When a command
- is issued, the interpreter 1) parses the full command line; 2) discards
- leading spaces; 3) indexes to the first space to identify the verb;
- 4) truncates the string if it's longer than four characters; 5) converts
- it to uppercase; 6) searches its lookup table of initial verbs; and,
- 7) gets down to business. If you write a long NOTE or "*" comment, the
- interpreter looks at every byte, savors a delicate sample, then spits
- it out. The same applies when you add a comment after ENDIF or ENDDO,
- or when you indent command lines for legibility.
- Take, for example, this simple iterative loop:
-
- variable_x=0
- DO WHILE variable_x<1000
- variable_x=variable_x+1
- *This is a long comment line
- *explaining what's going on
- ENDDO
-
- dCRUNCH shortens processing of this loop over 25 percent -- from
- 58 to 42 seconds. The biggest offender is the"*" line -- 13 seconds;
- a long comment tacked on to the ENDDO will have the same effect.
- Shortening "variable_x" to "x" shaves another 6 seconds.
- There is no measurable difference is one blank line is added, but
- a large overhead begins to accumulate with each additional blank line.
- Five blank lines increase execution time of 1,000 loops by 11 seconds.
- dCRUNCH's side effects are substantial. A program that is all-
- capitalized and left-justified without comments or mnemonic variable
- names is awful to read and a nightmare to modify 6 months later. And,
- in most applications, a few extra milliseconds inside a loop is the
- least of your problems. But if you need maximum speed inside an
- intensive loop -- like passing each record in a file -- dCRUNCH is
- just the ticket.
-
- - - - - -
- dCRUNCH.BAT:
-
- ECHO OFF
- REM dCRUNCH.BAT Speeds dBASE routines. Calls dSTRIP.COM
- IF %1/==/ GOTO noparm
- IF NOT EXIST dstrip.com GOTO nocom
- IF EXIST %1.prg GOTO strip
- ECHO -----
- ECHO File %1.PRG not found
- IF EXIST %1 ECHO Please specify the file without .PRG extension
- GOTO noparm
- :strip
- IF NOT EXIST %1.prk GOTO work
- ECHO -----
- ECHO A back-up file %1.PRK already exists and will be overwritten.
- ECHO Hit CTRL-BREAK followed by Y to interrupt or ...
- PAUSE
- DEL %1.prg
- :work
- ECHO Streamlining %1.prg. Original version is saved as %1.prk
- REN %1.prg %1.prk
- dstrip <%1.prk >%1.prg
- GOTO end
- :noparm
- ECHO SYNTAX: DCRUNCH [d:][path][filename] (omit ".prg" extension)
- GOTO end
- :nocom
- ECHO File DSTRIP.COM not found.
- :end
-
- - - - - -
- DSTRIP.ASM (to create DSTRIP.COM):
-
- ; DSTRIP - DOS filter to remove leading and trailing blanks, blank
- ; lines and comment lines from dBASE command files, and to
- ; capitalize text not in quotation marks.
- ;
- comseg segment para public 'code'
- assume cs:comseg,ds:comseg,es:comseg,ss:comseg
- org 100h
- start proc far
- cld
- mov bl,00000001b ;the bits in the BL register will hold
- ;the following information when set to 1:
- ;0-bit only tabs and blanks encountered
- ; in current line
- ;1-bit a '*' encountered as first
- ; character of line
- ;4-bit char inside 'single' quotes
- ;5-bit char inside "double" quotes
- ;6-bit last char was linefeed
- ;7-bit last char in *-line was a ';'
- xor dx,dx ;DX will count blanks/tabs after a char
- load: push bx ;save registers and
- push dx
- mov dx,offset data ;read into memory
- mov cx,64000 ;64K bytes
- xor bx,bx ;from standard input
- mov ah,3fh ;with DOS function call
- int 21h
- pop dx ;restore registers
- pop bx
- or ax,ax ;AX has number of bytes read; test for 0
- jnz load0
- jmp done
- load0: mov cx,ax ;move count into CX
- mov si,offset data ;and position index registers for
- mov di,offset data ;a string move
- scan0: lodsb ;fetch a byte into AL
- cmp al,26 ;end of file?
- jz store ;if so, store and get out
- test bl,01000000b ;LF on previous fetch?
- jz next ;if not, skip
- or bl,1 ;set beginning of line bit
- and bl,10111111b ;and reset the LF bit
- test bl,10000000b ;a ';' at end of line?
- jnz next0 ;if yes, skip
- and bl,11111101b ;otherwise reset '*'-bit
- next0: and bl,01111111b ;reset ';'-bit
- next: cmp al,59 ;a ';'?
- jnz next1 ;if not, skip
- or bl,10000000b ;set ';'-bit
- jmp short next5 ;and do loop routine
- next1: cmp al,32 ;blank?
- jz count ;if yes, check whether to count it
- cmp al,09 ;tab?
- jnz next2 ;if not, skip count
- count: test bl,11b ;are we at beginning of line or in a '*'-line?
- jnz loop ;if yes, loop and omit
- inc dx ;otherwise count the blank/tab
- jmp short store ;and store it
- next2: cmp al,13 ;CR?
- jz out ;if yes go to end of line routine
- next3: cmp al,10 ;LF?
- jnz next4 ;if not, go on checking
- or bl,01000000b ;set end of line bit
- jmp short out ;and go to end of line routine
- next4: test bl,1 ;have we seen any nonblank/tab char before?
- jz next6 ;if yes, ignore the next step
- cmp al,42 ;a '*'?
- jnz next5 ;if not, skip
- or bl,10b ;otherwise set the '*'-bit
- next5: and bl,11111110b ;and in either case we have nonblank/tab char
- next6: xor dx,dx ;set blank/tab count to 0
- out: test bl,11b ;are we at beginning of line or in a '*'-line?
- jnz loop ;if so, ignore (includes CR/LF of blank lines)
- sub di,dx ;DX is non-zero only if we encountered a CR
- xor dx,dx ;reset DX to 0
- and bl,01111111b ;reset ';'-bit
- caps0: jmp short caps ;capitalize
- store: stosb ;store char
- loop: cmp al,26 ;test for end of file
- loopnz scan0 ;and loop for next fetch
- push ax ;save registers
- push bx
- push dx
- mov dx,offset data ;compute the numbers of bytes stored
- mov cx,di
- sub cx,dx ;in CX, and
- mov bx,01 ;write to standard output
- mov ah,40h ;with DOS function call
- int 21h
- pop dx
- pop bx
- pop ax
- cmp al,26 ;end of file?
- jz done
- jmp load ;if not, read another 64K bytes
- done: int 20h ;end program
- caps: cmp al,39 ;single quote?
- jnz quot ;if not, check double quote
- test bl,100000b ;is double quote bit set?
- jnz store ;if yes, ignore
- xor bl,010000b ;(re-)set single quote bit
- jmp short store
- quot: cmp al,34 ;double quote?
- jnz caps01 ;if not, skip
- xor bl,00100000b ;(re-)set double-quote bit
- jmp short store
- caps01: test bl,00110000b ;any quote-bits set?
- jnz store ;if so, don't capitalize
- caps1: cmp al,97 ;below 'a'?
- jb store ;if so, leave it alone
- caps2: cmp al,122 ;above 'z'?
- ja store ;if so, don't change
- caps3: and al,5fh ;otherwise capitalize
- out2: jmp short store
- start endp
- data:
- comseg ends
- end start
-
-
- - - - - -
- You can use DEBUG to create DSTRIP.COM by issuing the command:
-
- DEBUG < DSTRIP.INP
-
- with the following. DEBUG will use DSTRIP.INP as its input to create
- the .COM file.
-
- N DSTRIP.COM
- A
- CLD
- MOV BL,01
- XOR DX,DX
- PUSH BX
- PUSH DX
- MOV DX,01CE
- MOV CX,FA00
- XOR BX,BX
- MOV AH,3F
- INT 21
- POP DX
- POP BX
- OR AX,AX
- JNZ 011C
- JMP 01A4
- MOV CX,AX
- MOV SI,01CE
- MOV DI,01CE
- LODSB
- CMP AL,1A
- JZ 0184
- TEST BL,40
- JZ 013F
- OR BL,01
- AND BL,BF
- TEST BL,80
- JNZ 013C
- AND BL,FD
- AND BL,7F
- CMP AL,3B
- JNZ 0148
- OR BL,80
- JMP 0171
- CMP AL,20
- JZ 0150
- CMP AL,09
- JNZ 0158
- TEST BL,03
- JNZ 0185
- INC DX
- JMP 0184
- CMP AL,0D
- JZ 0176
- CMP AL,0A
- JNZ 0165
- OR BL,40
- JMP 0176
- TEST BL,01
- JZ 0174
- CMP AL,2A
- JNZ 0171
- OR BL,02
- AND BL,FE
- XOR DX,DX
- TEST BL,03
- JNZ 0185
- SUB DI,DX
- XOR DX,DX
- AND BL,7F
- JMP 01A6
- STOSB
- CMP AL,1A
- LOOPNZ 0124
- PUSH AX
- PUSH BX
- PUSH DX
- MOV DX,01CE
- MOV CX,DI
- SUB CX,DX
- MOV BX,0001
- MOV AH,40
- INT 21
- POP DX
- POP BX
- POP AX
- CMP AL,1A
- JZ 01A4
- JMP 0105
- INT 20
- CMP AL,27
- JNZ 01B4
- TEST BL,20
- JNZ 0184
- XOR BL,10
- JMP 0184
- CMP AL,22
- JNZ 01BD
- XOR BL,20
- JMP 0184
- TEST BL,30
- JNZ 0184
- CMP AL,61
- JB 0184
- CMP AL,7A
- JA 0184
- AND AL,5F
- JMP 0184
-
- RCX
- 0CE
- W
- Q
-